/*
 * main.c
 *
 *  Created on: Apr 2, 2010
 *      Author: ren
 */

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>


//monitor RW_Controller {
//    int nr = 0, nw = 0; //(nr == 0 V nw == 0) ^ nw <= 1
//    cond oktoread,      //signaled when nw == 0
//        oktowrite;      //signaled when nr == 0 e nw == 0
//    procedure request_read() {
//        while (nw > 0) wait(oktoread);
//        nr = nr + 1;
//    }
//
//    procedure release_read() {
//        nr = nr - 1;
//        if (nr == 0) signal(oktowrite); //awaken one writer
//    }
//
//    procedure request_write() {
//        while (nr > 0 || nw > 0) wait (oktowrite);
//        nw = nw + 1;
//    }
//
//    procedure release_write() {
//        nw = nw - 1;
//        signal(oktowrite);      //awaken one writer and
//        signal_all(oktoread);   // all readers
//    }
//}

int escritores_juntos = 0;
int leitores_juntos = 0;


int nr = 0, nw = 0; //(nr == 0 V nw == 0) ^ nw <= 1
//cond oktoread,      //signaled when nw == 0
//oktowrite;      //signaled when nr == 0 e nw == 0

pthread_mutex_t rl = PTHREAD_MUTEX_INITIALIZER,
		wl = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t fim_escrita = PTHREAD_COND_INITIALIZER,
		fim_leitura = PTHREAD_COND_INITIALIZER;


void *Escritor(void *threadid)
{
    long tid;


    tid = (long)threadid;

    while (1) {
    	pthread_mutex_lock(&rl);
//    	printf("escritor ganha lock \n");
    	while (leitores_juntos > 0 || escritores_juntos > 0)
    		pthread_cond_wait(&fim_escrita,&rl);
//    	printf("escritor ganha condicional \n");
    	escritores_juntos++;
    	pthread_mutex_unlock(&rl);
    	printf("escritores %d leitores %d \n", escritores_juntos,leitores_juntos);
    	sleep(rand() % 5);
    	pthread_mutex_lock(&rl);
    	escritores_juntos--;
    	pthread_cond_signal(&fim_escrita);
//    	printf("escritor sinaliza \n");
    	pthread_mutex_unlock(&rl);
    	sleep(rand() % 5);
    }
}

void *Leitor(void *threadid)
{
    long tid;


    tid = (long)threadid;

    while (1) {
    	pthread_mutex_lock(&rl);
//    	printf("leitor ganha lock \n");
   		while (escritores_juntos > 0)
   			pthread_cond_wait(&fim_escrita,&rl);
//    	printf("leitor ganha condicional \n");
    	leitores_juntos++;
    	pthread_mutex_unlock(&rl);
    	printf("escritores %d leitores %d \n", escritores_juntos,leitores_juntos);
    	sleep(rand() % 5);
    	pthread_mutex_lock(&rl);
    	leitores_juntos--;
    	if (leitores_juntos == 0)
    		pthread_cond_signal(&fim_escrita);
//    	printf("leitor sinaliza \n");
    	pthread_mutex_unlock(&rl);
    	sleep(rand() % 5);
    }
}


int main(int argc, char *argv[])
{
	int leitores = atoi(argv[1]);
	int escritores = atoi(argv[2]);
    printf("Leitores-escritores! com %d leitores e %d escritores\n",leitores,escritores);

    pthread_t threads[leitores*escritores];

    pthread_attr_t thread_attr;

    int my_policy = 0;

    pthread_attr_init(&thread_attr);
    pthread_attr_getschedpolicy(&thread_attr,&my_policy);
    pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

    int rc;
    long t;

    for (t=0; t<leitores; t++)
    {
        printf("In main: creating thread %ld\n", t);
        rc = pthread_create(&threads[t], NULL, Leitor, (void *)t);

        if (rc)
        {
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    for (t=0; t<escritores; t++)
    {
        printf("In main: creating thread %ld\n", t);
        rc = pthread_create(&threads[t], NULL, Escritor, (void *)t);

        if (rc)
        {
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }
    pthread_exit(NULL);

    return 0;
}
